package com.echat.ebluetooth.service;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Message;
import android.os.SystemClock;
import android.support.annotation.Nullable;
import android.util.Log;
import android.widget.Toast;

import com.echat.ebluetooth.BaseApplication;
import com.echat.ebluetooth.bean.Beacon;
import com.echat.ebluetooth.constant.Constants;
import com.echat.ebluetooth.protocol.UDPClient;
import com.echat.ebluetooth.protocol.code.MsgEncoder;
import com.echat.ebluetooth.protocol.entity.BusinessData;
import com.echat.ebluetooth.protocol.entity.PackageData;
import com.echat.ebluetooth.util.PreferencesUtils;
import com.inuker.bluetooth.library.BluetoothClient;
import com.inuker.bluetooth.library.BluetoothService;
import com.inuker.bluetooth.library.search.SearchRequest;
import com.inuker.bluetooth.library.search.SearchResult;
import com.inuker.bluetooth.library.search.response.SearchResponse;
import com.inuker.bluetooth.library.utils.BluetoothUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import static com.echat.ebluetooth.constant.Constants.ACTION_REFRESH_UI;
import static com.echat.ebluetooth.constant.Constants.DEFAULT_SCREEN;
import static com.echat.ebluetooth.constant.Constants.DEFAULT_SERVER_HOST;
import static com.echat.ebluetooth.constant.Constants.DEFAULT_SERVER_PORT;
import static com.echat.ebluetooth.constant.Constants.KEY_ACCOUNT;
import static com.echat.ebluetooth.constant.Constants.KEY_HOST;
import static com.echat.ebluetooth.constant.Constants.KEY_PORT;
import static com.echat.ebluetooth.constant.Constants.KEY_SAVE;
import static com.echat.ebluetooth.constant.Constants.KEY_SCREEN;
import static com.echat.ebluetooth.constant.Constants.SEARCH_RESULT;

public class BluetoothSearchService extends Service implements Handler.Callback {

    private static final String TAG = "BluetoothSearchService";

    private static final int SEARCH_DURATION = 770; // 值为减掉关闭搜索耗时误差250ms
    private static final int SEARCH_INTERVAL = 1000;
    private static final int UPLOAD_INTERVAL = 2000;

    private BluetoothClient mBluetoothClient;

    private ArrayList<Beacon> mBeaconList;

    private HandlerThread mSearchThread;
    private Handler mHandler;

    private String mHost;
    private int mPort;
    private int mAccount;
    private String mScreen;
    private String mPhoneHost;
    private String mPhoneMac;

    private boolean isSave;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mBluetoothClient = BaseApplication.getBluetoothClient();
        mBeaconList = new ArrayList<>();
        mSearchThread = new HandlerThread(TAG);
        mSearchThread.start();
        mHandler = new Handler(mSearchThread.getLooper(), this);
        registerReceivers();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
//        searchAlarm(); // AlarmManager间隔时间必须 >= 5000ms
//        searchTimer(); // Timer没有AlarmManager稳定，在熄屏状态下可能停止运行
        isSave = (boolean) PreferencesUtils.get(this, KEY_SAVE, false);
        if(isSave){
            initConfig();
            startSearch();
        }
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        BluetoothUtils.unregisterReceiver(mReceiver);
        stopSearch();
        UDPClient.getInstance().close();
    }

    private void initConfig(){
        mHost = (String) PreferencesUtils.get(this, KEY_HOST, DEFAULT_SERVER_HOST);
        String port = (String) PreferencesUtils.get(this, KEY_PORT, String.valueOf(DEFAULT_SERVER_PORT));
        mPort = Integer.parseInt(port);
        String account = (String) PreferencesUtils.get(this, KEY_ACCOUNT, "");
        mAccount = Integer.parseInt(account);
        mScreen = (String) PreferencesUtils.get(this, KEY_SCREEN, DEFAULT_SCREEN);
        mPhoneHost = "00000000";
        mPhoneMac = "00000000000000000000";
    }

    private void registerReceivers(){
        IntentFilter filter = new IntentFilter();
        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
        BluetoothUtils.registerReceiver(mReceiver, filter);
    }

//    private void searchAlarm() {
//        AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
//        long triggerAtTime = SystemClock.elapsedRealtime() + UPLOAD_INTERVAL;
//        Intent i = new Intent(this, BluetoothSearchService.class);
//        PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
//        assert am != null;
//        if(Build.VERSION.SDK_INT < Build.VERSION_CODES.M){
//            am.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);
//        } else {
//            am.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);
//        }
//    }
//
//    private void searchTimer(){
//        Timer timer = new Timer();
//        timer.schedule(new TimerTask() {
//            @Override
//            public void run() {
//                startSearch();
//            }
//        }, 0, UPLOAD_INTERVAL);
//    }

    private void startSearch() {
        SearchRequest request = new SearchRequest.Builder()
                .searchBluetoothLeDevice(SEARCH_DURATION)
                .build();
        mBluetoothClient.search(request, mSearchResponse);
    }

    private void stopSearch(){
        mBluetoothClient.stopSearch();
    }

    private void addBeacon(Beacon beacon) {
        if(mScreen.equals(beacon.getAddress().substring(0, mScreen.length()))){
            Iterator<Beacon> iterator = mBeaconList.iterator();
            while(iterator.hasNext()){
                if(beacon.getAddress().equals(iterator.next().getAddress())){
                    iterator.remove();
                }
            }
            Log.i(TAG, "addBeacon: " + beacon.toString());
            mBeaconList.add(beacon);
        }
    }

    private void upload() {
        refreshUI();
        ArrayList<Beacon> uploadBeacons = new ArrayList<>();
        int num = mBeaconList.size() > 4 ? 4 : mBeaconList.size();
        for (int i = 0; i < num; i++) {
            uploadBeacons.add(mBeaconList.get(i));
        }
        PackageData packageData = formationPackageData(formationDataFields(uploadBeacons));
        byte[] data = MsgEncoder.encodePackageData(packageData);
        UDPClient.getInstance().send(mHost, mPort, data);
        //TODO: upload server
    }

    private void refreshUI() {
        Bundle bundle = new Bundle();
        bundle.putParcelableArrayList(SEARCH_RESULT, mBeaconList);

        Intent intent = new Intent();
        intent.setAction(ACTION_REFRESH_UI);
        intent.putExtras(bundle);
        sendBroadcast(intent);
    }

    /**
     * 包数据
     *
     * @param businessData 业务数据类
     * @return
     */
    private PackageData formationPackageData(BusinessData businessData) {
        PackageData data = new PackageData();
        data.setType(Constants.PROTOCOL_CONSTANT.TYPE);
        data.setSourceAddress(mPhoneHost);
        data.setDestinationAddress(mHost);
        data.setProtocolVer(Constants.PROTOCOL_CONSTANT.PROTOCOL_VER);
        data.setDataType((byte) 0x01);
        data.setPacketOrder(0);
        data.setSysTimer(System.currentTimeMillis());
        data.setUcMac(mPhoneMac);
        data.setReserve(Constants.PROTOCOL_CONSTANT.RESERVE);
        data.setBusinessData(MsgEncoder.encodeBusinessData(businessData));
        data.setEndByte(Constants.PROTOCOL_CONSTANT.END_BYTE);
        return data;
    }

    /**
     * 业务数据
     *
     * @param beaconList 信标集合
     * @return
     */
    private BusinessData formationDataFields(List<Beacon> beaconList) {
        BusinessData businessData = new BusinessData();
        businessData.setPkgHead(Constants.PROTOCOL_CONSTANT.PACKAGE_HEAD);
        businessData.setAccount(mAccount);
        businessData.setState((byte) 0xF0);
        businessData.setBeaconList(beaconList);
        return businessData;
    }

    private SearchResponse mSearchResponse = new SearchResponse() {
        @Override
        public void onSearchStarted() {
            Log.i(TAG, "onSearchStarted: 线程" + android.os.Process.myTid());
            mBeaconList.clear();
        }

        @Override
        public void onDeviceFounded(SearchResult device) {

            String name = device.getName();
            String address = device.getAddress();
            int rssi = device.rssi;
            Beacon beacon = new Beacon(name, address, rssi);
            addBeacon(beacon);
        }

        @Override
        public void onSearchStopped() {
            mHandler.postDelayed(runnable, SEARCH_INTERVAL);
            Log.i(TAG, "onSearchStopped: 线程" + android.os.Process.myTid());
            Collections.sort(mBeaconList, new SignalComparator());
            upload();
        }

        @Override
        public void onSearchCanceled() {
        }
    };

    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            Log.i(TAG, "run: 线程" + android.os.Process.myTid());
            startSearch();
        }
    };

    @Override
    public boolean handleMessage(Message msg) {
        return false;
    }

    class SignalComparator implements Comparator<Beacon> {

        @Override
        public int compare(Beacon o1, Beacon o2) {
            return Integer.compare(o2.getRssi(), o1.getRssi());
        }
    }

    BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
            switch (state) {
                case BluetoothAdapter.STATE_ON:
                    Log.i(TAG, "onReceive: 蓝牙开启");
                    if(!isSave){
                        Toast.makeText(context, "未配置设备信息！", Toast.LENGTH_SHORT).show();
                    }
                    startSearch();
                    Toast.makeText(BluetoothSearchService.this, "蓝牙已开启", Toast.LENGTH_SHORT).show();
                    break;
                case BluetoothAdapter.STATE_TURNING_ON:
                    Log.i(TAG, "onReceive: 蓝牙正在开启");
                    break;
                case BluetoothAdapter.STATE_OFF:
                    Log.i(TAG, "onReceive: 蓝牙关闭");
                    stopSearch();
                    Toast.makeText(BluetoothSearchService.this, "蓝牙已关闭", Toast.LENGTH_SHORT).show();
                    break;
                case BluetoothAdapter.STATE_TURNING_OFF:
                    Log.i(TAG, "onReceive: 蓝牙正在关闭");
                    break;
            }
        }
    };

}
